﻿#region License

// Created by John Batte on 04/22/2012 at 11:38 AM.
// Last code cleanup: 04/22/2012 at 12:23 PM.
// 
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

#endregion

using System;
using System.Reactive.Subjects;

using BatteCode.Fx.ExceptionHandling;
using BatteCode.Fx.Reactive;

namespace BatteCode.Fx.Plugins.Automation
{
	/// <summary>
	/// 	Defines a context for plugin automation.
	/// </summary>
	public class AutomationContext
	{
		#region subjects
		private readonly Subject<CallRequest> _callRequests = new Subject<CallRequest>();
		private readonly Subject<CallResponse> _callResponses = new Subject<CallResponse>();
		private readonly Subject<PluginError> _errors = new Subject<PluginError>();
		private readonly Subject<ReadRequest> _readRequests = new Subject<ReadRequest>();
		private readonly Subject<ReadResponse> _readResponses = new Subject<ReadResponse>();
		private readonly Subject<WriteRequest> _writeRequests = new Subject<WriteRequest>();
		private readonly Subject<WriteResponse> _writeResponses = new Subject<WriteResponse>();
		#endregion

		#region feeds
		/// <summary>
		/// 	Gets the call requests.
		/// </summary>
		public IObservable<CallRequest> CallRequests
		{
			get { return _callRequests; }
		}

		/// <summary>
		/// 	Gets the call responses.
		/// </summary>
		public IObservable<CallResponse> CallResponses
		{
			get { return _callResponses; }
		}

		/// <summary>
		/// 	Gets the read requests.
		/// </summary>
		public IObservable<ReadRequest> ReadRequests
		{
			get { return _readRequests; }
		}

		/// <summary>
		/// 	Gets the read responses.
		/// </summary>
		public IObservable<ReadResponse> ReadResponses
		{
			get { return _readResponses; }
		}

		/// <summary>
		/// 	Gets the write requests.
		/// </summary>
		public IObservable<WriteRequest> WriteRequests
		{
			get { return _writeRequests; }
		}

		/// <summary>
		/// 	Gets the write responses.
		/// </summary>
		public IObservable<WriteResponse> WriteResponses
		{
			get { return _writeResponses; }
		}

		/// <summary>
		/// 	Gets the errors.
		/// </summary>
		public IObservable<PluginError> Errors
		{
			get { return _errors; }
		}
		#endregion

		#region automation
		/// <summary>
		/// 	Runs the specified read request.
		/// </summary>
		/// <param name="request"> The request. </param>
		/// <param name="readLogic"> The read logic. </param>
		/// <returns> </returns>
		public ReadResponse Read(ReadRequest request, Func<ReadRequest, ReadResponse> readLogic)
		{
			_readRequests.PushNextResult(request);
			ReadResponse response = Try.Get(() => readLogic(request), ex =>
			{
				_errors.PushNextResult(new PluginError(ex));
				return new ExceptionState(ex, true);
			});
			_readResponses.PushNextResult(response);
			return response;
		}

		/// <summary>
		/// 	Runs the specified write request.
		/// </summary>
		/// <param name="request"> The request. </param>
		/// <param name="writeLogic"> The write logic. </param>
		/// <returns> </returns>
		public WriteResponse Write(WriteRequest request, Func<WriteRequest, WriteResponse> writeLogic)
		{
			_writeRequests.PushNextResult(request);
			WriteResponse response = Try.Get(() => writeLogic(request), ex =>
			{
				_errors.PushNextResult(new PluginError(ex));
				return new ExceptionState(ex, true);
			});
			_writeResponses.PushNextResult(response);
			return response;
		}

		/// <summary>
		/// 	Runs the specified call request.
		/// </summary>
		/// <param name="request"> The request. </param>
		/// <param name="callLogic"> The call logic. </param>
		/// <returns> </returns>
		public CallResponse Call(CallRequest request, Func<CallRequest, CallResponse> callLogic)
		{
			_callRequests.PushNextResult(request);
			CallResponse response = Try.Get(() => callLogic(request), ex =>
			{
				_errors.PushNextResult(new PluginError(ex));
				return new ExceptionState(ex, true);
			});
			_callResponses.PushNextResult(response);
			return response;
		}
		#endregion
	}
}